﻿using System;
using System.Security.Cryptography;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Text.RegularExpressions;

namespace BookTheBook.Amazon
{
    internal class AmazonSigningMessageInspector : IClientMessageInspector
    {
        private readonly string _accessKeyId;
        private readonly string _secretKeyId;

        public AmazonSigningMessageInspector(string accessKeyId, string secretKeyId)
        {
            _accessKeyId = accessKeyId;
            _secretKeyId = secretKeyId;
        }

        /// <summary>
        /// Before request is sent we need to sign it, as in Using SOAP without WS-Security section in
        /// http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?RequestAuthenticationArticle.html
        /// This justifies algorithm types and timestamp format used.
        /// </summary>
        /// <param name="request">This is a message that is send between endpoints in distributed environment.</param>
        /// <param name="channel">Defines the behavior of outbound request and request/reply channels used by client applications.</param>
        /// <returns>Generally instance of object type, but in our case - null. After signed signature header is added, our job is done.</returns>
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            string operation = Regex.Match(request.Headers.Action, "[^/]+$").ToString();

            DateTime now = DateTime.UtcNow;
            string timestamp = now.ToString("yyyy-MM-ddTHH:mm:ssZ");
            string toBeSigned = operation + timestamp;
            byte[] bytesToBeSigned = Encoding.UTF8.GetBytes(toBeSigned);

            byte[] secretKeyIdBytes = Encoding.UTF8.GetBytes(_secretKeyId);
            HMAC hmac = new HMACSHA256(secretKeyIdBytes);
            byte[] hashBytes = hmac.ComputeHash(bytesToBeSigned);
            string signature = Convert.ToBase64String(hashBytes);

            request.Headers.Add(new AmazonMessageHeader("AWSAccessKeyId", _accessKeyId));
            request.Headers.Add(new AmazonMessageHeader("Timestamp", timestamp));
            request.Headers.Add(new AmazonMessageHeader("Signature", signature));

            return null;
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
        }
    }
}